#include "pxa_udcbits.h"
#include "util.h"
#include "xllp_u2d.h"
#include "xllp_mfp_plat_L_LV.h"
#include "xllp_gpio.h"

#define CONFIG_CPU_MONAHANS_LV

#define ELRUDC_DBG 0
#if ELRUDC_DBG
#define DBGOUT(x) x
#else
#define DBGOUT(x)     /* gcc will remove all the debug code for us */
#endif


XLLP_STATUS_T xllp_max7320_write(XLLP_UINT8_T reg, XLLP_UINT8_T val);
XLLP_STATUS_T xllp_max7320_read(XLLP_UINT8_T reg, XLLP_UINT8_T *pval);

/////////////////////////////////////////////////////////////////////
/*!
    Initialize pU2DHandle.
@param[out] pU2DHandle      A point to XLLP_U2D_T. The buffer is provide by driver
@param[in]  pU2DBase        U2D virtual base address
@param[in]  pMfpRegBase     MFP virtual base address
@param[in]  pGPIORegs       GPIO vittual base address
@param[in]  pMfRmDb         MFP Resource manage address.

@remarks
    This funtion must be call before u2d function

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/
XLLP_STATUS_T XllpU2DInitHandle(P_XLLP_U2D_T pU2DHandle, P_XLLP_U2D_REGISTERS_T pU2DBase, P_XLLP_VUINT32_T pMfpRegBase,
                                P_XLLP_GPIO_T pGPIORegs,P_XLLP_MFP_RM_DB_ID_T pMfRmDb)
{

    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }
    memset(pU2DHandle, 0, sizeof(XLLP_U2D_T));

    pU2DHandle->pRegsBase   = pU2DBase;
    pU2DHandle->pMfpRegBase = pMfpRegBase;
    pU2DHandle->pGPIORegs   = pGPIORegs;
    pU2DHandle->pMfpRmDb    = pMfRmDb;

    //Verify U2D Register define is correct
    U2D_DBG(("u2disr: %d\r\n", U2D_OFFSET(u2disr)==0xC?1:0));
    U2D_DBG(("u2dcsr0: %d\r\n", U2D_OFFSET(u2dcsr[0])==0x100?1:0));

    U2D_DBG(("u2dbcr0: %d\r\n", U2D_OFFSET(u2dbcr[0])==0x200?1:0));

    U2D_DBG(("u2ddr0: %d\r\n", U2D_OFFSET(u2ddr[0])==0x300?1:0));

    U2D_DBG(("u2dcrA: %d\r\n", U2D_OFFSET(u2dcr[1])==0x404?1:0));
    U2D_DBG(("u2dcrA offset: %d\r\n", U2D_OFFSET(u2dcr[1])));

    U2D_DBG(("u2dsca: %d\r\n", U2D_OFFSET(u2dsca)==0x500?1:0));

    U2D_DBG(("u2dmacsr0: %d\r\n", U2D_OFFSET(u2ddmacsr[0])==0x1000?1:0));

    U2D_DBG(("u2dmacr: %d\r\n", U2D_OFFSET(u2ddmacr)==0x1080?1:0));

    U2D_DBG(("u2dmaint: %d\r\n", U2D_OFFSET(u2dmaint)==0x10F0?1:0));

    U2D_DBG(("u2dmadadr0: %d\r\n", U2D_OFFSET(ddg[0])==0x1200?1:0));

    return XLLP_STATUS_SUCCESS;
}

/*!
    Set one endpoint's FIFO size and enable memory allocation

@remarks
    Endpoint 0 needn't config

@param[in]  pU2DHandle  U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  EP          Endpoint Number
@param[in]  pConfig     Point to config data. @see XLLP_U2D_EP_CONFIG for detail infomation

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/


XLLP_STATUS_T XllpU2DEndpointSetConfig(P_XLLP_U2D_T pU2DHandle, XLLP_U2D_EP_T EP, P_XLLP_U2D_EP_CONFIG pConfig)
{
    P_XLLP_U2D_REGISTERS_T pReg;
    XLLP_INT_T ep = EP;

    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    if(ep<0) {
        U2D_DBG(("%s EP Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    if(ep>=XLLP_U2D_USB_MAX_EP_NUM) {
        U2D_DBG(("%s EP Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    pReg=pU2DHandle->pRegsBase;

    pU2DHandle->ConfigTable[EP]=*pConfig;

    pReg->u2dcr[EP] =   (pConfig->bufferSize>>2)|0x1;

    U2D_DBG(("%s U2DCR[%d](%x) : 0x%X\r\n", __FUNCTION__, EP, &pReg->u2dcr[EP], pReg->u2dcr[EP] ));

    return XLLP_STATUS_SUCCESS;
}

/*!
    Set one endpoint's property, inclued EN, ET, CN, IN, ASIN, etc

@remarks
    Endpoint 0 needn't config

@param[in]  pU2DHandle  U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  EP          Endpoint Number
@param[in]  pConfig     Point to config data. @see XLLP_U2D_EP_CONFIG for detail infomation

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/


XLLP_STATUS_T XllpU2DEndpointSetInfo(P_XLLP_U2D_T pU2DHandle, XLLP_U2D_EP_T EP, P_XLLP_U2D_EP_CONFIG pConfig)
{
    P_XLLP_U2D_REGISTERS_T pReg;
    XLLP_INT_T ep = EP;

    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    if(ep<0) {
        U2D_DBG(("%s EP Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    if(ep>=XLLP_U2D_USB_MAX_EP_NUM) {
        U2D_DBG(("%s EP Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    pReg=pU2DHandle->pRegsBase;

    pU2DHandle->ConfigTable[EP]=*pConfig;

    pReg->u2dne[EP] =   (pConfig->EN<<0 ) |
                        (pConfig->ED <<4)|
                        (pConfig->ET <<5)|
                        (pConfig->CN <<7)|
                        (pConfig->InterfaceNumber<<11)|
                        (pConfig->AISN <<15)|
                        (pConfig->MPS <<19)|
                        (pConfig->HBW<<30);

    //U2D_DBG(("%s U2DNE[%d] : 0x%X\r\n", __FUNCTION__, EP, pReg->u2dne[EP] ));

    return XLLP_STATUS_SUCCESS;
}

/*!
    Clear all enpoint configuration

@param[in]  pU2DHandle  U2DHandle, which is initilizated in XllpU2DInitHandle

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/
XLLP_STATUS_T XllpU2DClearAllConfigure(P_XLLP_U2D_T pU2DHandle)
{
    int i=0;
    P_XLLP_U2D_REGISTERS_T pReg;

    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    pReg=pU2DHandle->pRegsBase;

    for(i=U2D_ENDPOINT_A;i<XLLP_U2D_USB_MAX_EP_NUM;i++) {
        pReg->u2dne[i] = 0;
        pReg->u2dcr[i] = 0;

        memset(pU2DHandle->ConfigTable+i, 0, sizeof(XLLP_U2D_EP_CONFIG));
        memset(pU2DHandle->u2dEpXferTable+i, 0, sizeof(XLLP_U2D_TRANSFER_T));
    }

    return XLLP_STATUS_SUCCESS;
}

/*!
    Enable U2D Controller

@param[in] pU2DHandle   U2DHandle, which is initilizated in XllpU2DInitHandle

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/
XLLP_STATUS_T XllpU2DEnable(P_XLLP_U2D_T pU2DHandle)
{
    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }
    pU2DHandle->pRegsBase->u2dctrl |= XLLP_U2DCR_UDE;

    return XLLP_STATUS_SUCCESS;
}



/*!
    Disable U2D Controller

@param[in]  pU2DHandle   U2DHandle, which is initilizated in XllpU2DInitHandle

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/
XLLP_STATUS_T XllpU2DDisable (P_XLLP_U2D_T pU2DHandle)
{
    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }
    pU2DHandle->pRegsBase->u2dctrl &= ~XLLP_U2DCR_UDE;
    return XLLP_STATUS_SUCCESS;
}

/*!
    Enable U2D interrupt including U2D DMA Interupt

@param[in]  pU2DHandle      U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum  Enpoint Number.
@param[in]  interruptType   Bit mask, Interrutp Type  @see XLLP_U2D_EP_INTERRUPT_TYPE_T

@remarks
    if pU2DHandle larger than U2D_INT_ENDPOINT_G. interruptType willnot be cared.

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/


XLLP_STATUS_T XllpU2DEnableInterrupt (P_XLLP_U2D_T pU2DHandle,
                             XLLP_U2D_INTERRUPTS_T udcEndpointNum,
                             XLLP_U2D_EP_INTERRUPT_TYPE_T interruptType)
{
    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }
    if( udcEndpointNum >= U2D_INT_RESET ) {
        pU2DHandle->pRegsBase->u2dicr |=  1<<udcEndpointNum;
        return XLLP_STATUS_SUCCESS;
    }

    if( interruptType&U2D_SHORT_PACKET_COMPL_INT ) {
        pU2DHandle->pRegsBase->u2dicr |=    U2D_SHORT_PACKET_COMPL_INT<<(udcEndpointNum*3);
    }
    if( interruptType&U2D_PACKET_COMPL_INT ) {
        pU2DHandle->pRegsBase->u2dicr |=    U2D_PACKET_COMPL_INT<<(udcEndpointNum*3);
    }
    if( interruptType&U2D_FIFO_ERROR_INT ) {
        pU2DHandle->pRegsBase->u2dicr |=    U2D_FIFO_ERROR_INT<<(udcEndpointNum*3);
    }

    pU2DHandle->pRegsBase->u2ddmacsr[udcEndpointNum] |= interruptType&(U2D_DMA_STOP|U2D_DMA_EOR|U2D_DMA_EORJMP|U2D_DMA_EORSTOP|U2D_DMA_RAS);

//  printf("u2dicr = %x, dmacsrA = %x\n", pU2DHandle->pRegsBase->u2dicr, pU2DHandle->pRegsBase->u2ddmacsr[udcEndpointNum]);

    return XLLP_STATUS_SUCCESS;
}


/*!
    Disable U2D interrupt including U2D DMA Interupt

@param[in]  pU2DHandle      U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum  Enpoint Number.
@param[in]  interruptType   Bit mask, Interrutp Type  @see XLLP_U2D_EP_INTERRUPT_TYPE_T

@remarks
    if pU2DHandle larger than U2D_INT_ENDPOINT_G. interruptType will not be cared.

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/

XLLP_STATUS_T XllpU2DDisableInterrupt  (P_XLLP_U2D_T pU2DHandle,
                             XLLP_U2D_INTERRUPTS_T udcEndpointNum,
                             XLLP_U2D_EP_INTERRUPT_TYPE_T interruptType)
{
    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }
    if( udcEndpointNum >= U2D_INT_RESET ) {
        pU2DHandle->pRegsBase->u2dicr &= ~( 1<<udcEndpointNum );
        return XLLP_STATUS_SUCCESS;
    }

    if( interruptType&U2D_SHORT_PACKET_COMPL_INT ) {
        pU2DHandle->pRegsBase->u2dicr &= ~(U2D_SHORT_PACKET_COMPL_INT<<(udcEndpointNum*3));
    }
    if( interruptType&U2D_PACKET_COMPL_INT ) {
        pU2DHandle->pRegsBase->u2dicr &= ~(U2D_PACKET_COMPL_INT<<(udcEndpointNum*3));
    }
    if( interruptType&U2D_FIFO_ERROR_INT ) {
        pU2DHandle->pRegsBase->u2dicr &= ~(U2D_FIFO_ERROR_INT<<(udcEndpointNum*3));
    }

    pU2DHandle->pRegsBase->u2ddmacsr[udcEndpointNum] &= ~(interruptType&(U2D_DMA_STOP|U2D_DMA_EOR|U2D_DMA_EORJMP|U2D_DMA_EORSTOP|U2D_DMA_RAS));

    return XLLP_STATUS_SUCCESS;
}


/*!
    U2D config change call back function
    Driver Interrutp handle call this file if U2D_INT_CONFIG happen

@param[in]  pU2DHandle      U2DHandle, which is initilizated in XllpU2DInitHandle

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/
XLLP_STATUS_T XllpU2DConfigChangeCallback (P_XLLP_U2D_T pU2DHandle)
{
    XLLP_UINT32_T config, udcCR;

    udcCR = pU2DHandle->pRegsBase->u2dctrl;

    // Read current active configuration number.
    config = (udcCR & XLLP_U2DCR_ACN_MASK)>>XLLP_U2DCR_ACN_SHIFT;
    pU2DHandle->usbConfigNumActive = ( XLLP_UINT8_T )config;

    // Read latest changed interface number.
    pU2DHandle->usbInterfaceNumChanged = (XLLP_UINT8_T) ((udcCR & XLLP_U2DCR_AIN_MASK) >> XLLP_U2DCR_AIN_SHIFT);

    // Read selected alt setting for that interface.
    pU2DHandle->usbIntAltSettingsNumSelected = (XLLP_UINT8_T) ((udcCR & XLLP_U2DCR_AAISN_MASK) >> XLLP_U2DCR_AAISN_SHIFT);

    // Switch Endpoint memory to active configuration
    //pU2DHandle->pRegsBase->u2dctrl|= XLLP_U2DCR_SMAC;


    return XLLP_STATUS_SUCCESS;
}


/*!
    Force Endpoint Stall

@param[in]  pU2DHandle      U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum  End point Number

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/
XLLP_STATUS_T XllpU2DForceEndpointStall (P_XLLP_U2D_T pU2DHandle,
                                XLLP_U2D_EP_T udcEndpointNum)
{

    volatile P_XLLP_U2D_REGISTERS_T pRegs = (P_XLLP_U2D_REGISTERS_T)pU2DHandle->pRegsBase;

    pRegs->u2dcsr[udcEndpointNum] =
          (pRegs->u2dcsr[udcEndpointNum] & XLLP_U2DCCSR_RW_BITS_MASK) | XLLP_U2DCCSR_FST;

    return XLLP_STATUS_SUCCESS;
}


/*!
    Flush Endpoint FIFO

@remarks
    U2D DMA Channel will reset

@param[in]  pU2DHandle      U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum  End point Number

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/
XLLP_STATUS_T XllpU2DFlushEndpointFifo (P_XLLP_U2D_T pU2DHandle,
                                XLLP_U2D_EP_T udcEndpointNum)
{
    volatile P_XLLP_U2D_REGISTERS_T pRegs = (P_XLLP_U2D_REGISTERS_T)pU2DHandle->pRegsBase;

    pRegs->u2dcsr[udcEndpointNum] =
          (pRegs->u2dcsr[udcEndpointNum] & XLLP_U2DCCSR_RW_BITS_MASK) | XLLP_U2DCCSR_FEF;

    return XLLP_STATUS_SUCCESS;
}


/*!
    Start U2D DMA transfer.

@remarks
    Call such this function before call XllpU2DStartTransfer.
    U2D support DMA transfer.

@param[in]  pU2DHandle              U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum          End point Number
@param[in]  physicalAddress         Physical address. Physcial continue.
@param[in]  len                     Buffer Size
@param[in]  direct                  Transfer direct IN or OUT
@param[in]  isZeroPackage           Only valid for IN transfer.
                                    -   TRUE    send zero package if len is multiply package size
                                    -   Don't send zero package


@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail

*/
XLLP_STATUS_T XllpU2DStartTransfer (P_XLLP_U2D_T pU2DHandle,
                 P_XLLP_U2D_TRANSFER pTransfer)
{
    DBGOUT(printf("^^^^^^In XllpU2DStartTransfer\n"));
    XLLP_UINT32_T i=0;
    XLLP_UINT32_T udcEndpointNum=pTransfer->udcEndpointNum;
    XLLP_UINT32_T DescCount  =pU2DHandle->ConfigTable[udcEndpointNum].nDescriptors;
    XLLP_UINT32_T PackageSize=pU2DHandle->ConfigTable[udcEndpointNum].MPS;
    XLLP_DMAC_DESCRIPTOR_T *Desc=pU2DHandle->ConfigTable[udcEndpointNum].vDmaDescriptor;
    XLLP_UINT32_T DescPhy=(XLLP_UINT32_T)(pU2DHandle->ConfigTable[udcEndpointNum].pDmaDescriptor);
    XLLP_UINT32_T physicalAddress=pTransfer->physicalAddress;
    XLLP_UINT32_T len=pTransfer->len;
    XLLP_UDC_EP_DIR_T direct=pTransfer->direct;
    XLLP_VUINT32_T dumy;

    DBGOUT(printf("EndpointNum: %d, DescCount: %d, PackageSize: %d, descv: %x, DescPhy: %x, physicalAddress:%x, len: %d, direct: %d\n",
        udcEndpointNum, DescCount, PackageSize, Desc, DescPhy, physicalAddress, len, direct));

    pU2DHandle->pRegsBase->ddg[udcEndpointNum].ddadr=DescPhy;

    DBGOUT(printf("the endpoint A info register: %x, dmadadrA :%x\n", U2DENA, U2DMADADR(1)));
    DBGOUT(printf("the endpoint B info register: %x, dmadadrB :%x\n", U2DENB, U2DMADADR(2)));
    /*U2D_DBG(("%s:ep%d, len%d, MPS%d\n", __FUNCTION__, udcEndpointNum, len, PackageSize));*/

    for(i=0;i<DescCount;i++) {
        DescPhy+=sizeof(XLLP_DMAC_DESCRIPTOR_T);

        Desc->ddadr = DescPhy;
        Desc->dcmd  = 0;

        if(direct) {//IN
            Desc->dsadr = physicalAddress;
            Desc->dcmd |= XLLP_U2DDMA_CMD_XFRDIS;
        }
        else {//Out
            Desc->dtadr = physicalAddress;
        }

        if(len>=PackageSize) {
            Desc->ddadr &= ~XLLP_DMAC_DDADR_STOP;
            Desc->dcmd|=PackageSize;
            len -= PackageSize;

        }
        else {
            Desc->dcmd|=len;
            Desc->ddadr|= XLLP_DMAC_DDADR_STOP;
            if(pTransfer->EnableEndIrq) {
                DBGOUT(printf("XLLP_U2DDMA_CMD_ENDIRQEN enable!\n"));
                Desc->dcmd|=XLLP_U2DDMA_CMD_ENDIRQEN;  //why interrupt in bootloader???
            }

            if(direct) { //IN
                if(len>0) {
                    DBGOUT(printf("Not the zero packet!\n"));
                    Desc->dcmd |= XLLP_U2DDMA_CMD_PACKCOMP; //send short package
                }
                else {// if(pTransfer->isZeroPackage)
                    //Send Zero package
                    DBGOUT(printf("Is the zero packet!\n"));
                    Desc->dcmd |= XLLP_U2DDMA_CMD_PACKCOMP; //send zero package
                }
            }
            len = 0;
        }

        //read back to make sure ddadr have been writed before start DMA
        dumy = Desc->dcmd;
        dumy = Desc->ddadr;
        dumy = Desc->dsadr;
        dumy = Desc->dtadr;
        DBGOUT(printf("dcmd: %x, ddadr: %x, dsadr: %x, dtadr: %x\n", Desc->dcmd, Desc->ddadr, Desc->dsadr, Desc->dtadr));

        physicalAddress += PackageSize;
        Desc++;
        if (!len)
            break;

    }
    (Desc-1)->ddadr |= XLLP_DMAC_DDADR_STOP;

    //read back to make sure ddadr have been writed before start DMA
    dumy = (Desc-1)->ddadr;
    DBGOUT(printf("the last descriptor DDADR: %x\n", dumy));

    return XLLP_STATUS_SUCCESS;
}

/*!
    Get U2D Transfer Status

@param[in]  pU2DHandle              U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]  udcEndpointNum          End point Number
@param[in]  length                  length have transfered by U2D

@return
    - XLLP_STATUS_SUCCESS   Success
    - Other value           Fail
*/
XLLP_STATUS_T XllpU2DGetTransferStatus (P_XLLP_U2D_T pU2DHandle,
                                        XLLP_U2D_EP_T udcEndpointNum,
                                        XLLP_UINT32_T * length
                                        )
{

    XLLP_UINT32_T DescE, DescS;
    XLLP_UINT32_T LastN;
    int PackageSize=pU2DHandle->ConfigTable[udcEndpointNum].MPS;
    XLLP_DMAC_DESCRIPTOR_T *Desc=pU2DHandle->ConfigTable[udcEndpointNum].vDmaDescriptor;

    if(!length) {
        U2D_DBG(("%s length Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    DescS=(XLLP_UINT32_T)(pU2DHandle->ConfigTable[udcEndpointNum].pDmaDescriptor);
    DescE=pU2DHandle->pRegsBase->ddg[udcEndpointNum].ddadr;

    LastN=(DescE-DescS)/sizeof(XLLP_DMAC_DESCRIPTOR_T);
    LastN--;

    *length=LastN*PackageSize+(Desc[LastN].dcmd&XLLP_U2DDAM_CMD_LEN_MASK)-(pU2DHandle->pRegsBase->ddg[udcEndpointNum].dcmd&XLLP_U2DDAM_CMD_LEN_MASK);

    return  XLLP_STATUS_SUCCESS;
}


/*!

    This function writes the specified number of bytes to the Endpoint's FIFO.\

@remarks
    Only Support Ep0
    Since the proccessor core cannot issue writes of size 3 bytes, when bit IPA is set it substracts 1 byte
    from a processor wirte to the Endpoint 0 Data Register U2DDR0.

    When len&0x3 == 3, you need set IPA and IPR

@param[in]    pU2DHandle            U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]    udcEndpointNum        End point Number
@param[in]    src                   a pointer to the data buffer
@param[in]    len                   number of bytes to write

@return
    lenth have been writen to FIFO

*/

XLLP_INT32_T XllpU2DWriteDwordFifo(P_XLLP_U2D_T pU2DHandle, XLLP_U2D_EP_T udcEndpointNum, P_XLLP_UINT8_T src, XLLP_INT32_T len)
{
    XLLP_INT32_T    i;
    XLLP_UINT32_T   temp[16];
    P_XLLP_UINT32_T p1;
    P_XLLP_VUINT8_T pBuff, pTemp;
    P_XLLP_VUINT32_T pReg=pU2DHandle->pRegsBase->u2ddr;

    if(udcEndpointNum!=U2D_ENDPOINT_0) {
        U2D_DBG(("%s udcEndpointNum Invalidata\r\n",__FUNCTION__));
        return -1;
    }

    if (len == 0) {
        return 0;
    }
    if( len > sizeof(temp) ) {
        len = sizeof(temp);
    }

    if ((XLLP_UINT32_T) src & 0x3) {
        i = len;
        pBuff = (P_XLLP_VUINT8_T)src;
        pTemp = (P_XLLP_VUINT8_T)temp;
        while(i-- > 0) *(pTemp+i) = *(pBuff +i);
//      memcpy (temp, src, len);
        p1 = temp;

    }
    else {
        p1 = (P_XLLP_UINT32_T)src;
    }

    if (((XLLP_INT32_T) len & 0x3) == 0) {
        // 4 byte aligned
        for (i=0; i<(len>>2); i++) {
            *pReg = *p1++;
        }
    }
    else {
        for (i=0; i<(len>>2); i++) {
            // all words
            *pReg = *p1++;
        }

        if ( (len&0x3) == 2) {
            *(P_XLLP_VUINT16_T)pReg=*(P_XLLP_VUINT16_T)p1;
        }
        if ( (len&0x3) == 1) {
            *(P_XLLP_VUINT8_T)pReg=*(P_XLLP_VUINT8_T)p1;
        }

        if ( (len&0x3) == 3) {
            *(P_XLLP_VUINT32_T)pReg=*(P_XLLP_VUINT32_T)p1;
        }

    }
    return len;
}

/*!

    This function read the specified number of bytes to the Endpoint's FIFO.

@remarks
    Only Support Ep0

@param[in]    pU2DHandle            U2DHandle, which is initilizated in XllpU2DInitHandle
@param[in]    udcEndpointNum        End point Number
@param[in]    buf                   a pointer to the data buffer
@param[in]    len                   number of bytes to write

@return
    lenth have been writen to FIFO
*/
XLLP_INT32_T XllpU2DReadDwordFifo(P_XLLP_U2D_T pU2DHandle, XLLP_U2D_EP_T udcEndpointNum, P_XLLP_UINT8_T buf, XLLP_INT32_T len)
{
    XLLP_INT32_T    i;
    XLLP_UINT32_T   temp[16], rdat;
    P_XLLP_UINT32_T p1;
    XLLP_BOOL_T     copyback;
    P_XLLP_VUINT8_T pBuff, pTemp;

    P_XLLP_VUINT32_T pReg=pU2DHandle->pRegsBase->u2ddr;

    if(udcEndpointNum!=U2D_ENDPOINT_0) {
        U2D_DBG(("%s udcEndpointNum Invalidata\r\n",__FUNCTION__));
        return -1;
    }
    if( len > sizeof(temp) ) {
        len = sizeof(temp);
    }

    if (((XLLP_UINT32_T)buf & 0x3) != 0) {
        p1 = temp;
        copyback = XLLP_TRUE;
    }
    else {
        p1 = (P_XLLP_UINT32_T)buf;
        copyback = XLLP_FALSE;
    }


    if (((XLLP_INT32_T)len & 0x3) == 0) {
        // 4 byte aligned
        for (i=0; i<(len>>2); i++) {
            *p1++ = *pReg;
        }
    }
    else {
        for (i=0; i<(len>>2); i++) {
            // all words
            *p1++ = *pReg;
        }
        rdat = *pReg;

        pBuff = (P_XLLP_VUINT8_T)p1;
        pTemp = (P_XLLP_VUINT8_T)&rdat;

        for (i=0; i<(len&0x3); i++) {
           *pBuff++ = *pTemp++;
        }
    }

    if (copyback) {
        i = len;
        pBuff = (P_XLLP_VUINT8_T)buf;
        pTemp = (P_XLLP_VUINT8_T)temp;
        while(i-- > 0)
            *(pBuff + i) = *(pTemp + i);
//      memcpy (buf, temp, len);
    }
    return len;
}


XLLP_STATUS_T XllpU2DBusDevSoftConnect(P_XLLP_U2D_T pU2DHandle, XLLP_BOOL_T connect)
{
    if(!pU2DHandle) {
        U2D_DBG(("%s pU2DHandle Invalidata\r\n",__FUNCTION__));
        return XLLP_STATUS_FAILURE;
    }

    if (connect == XLLP_TRUE) {
        // Pull up the D+ pin at the internal transceiver.
        pU2DHandle->pRegsBase->u2dctrl &= ~XLLP_U2DCR_ADD;
    }
    else {
        // Float the D+,D- pin at the internal transceiver.
        pU2DHandle->pRegsBase->u2dctrl |= XLLP_U2DCR_ADD;
    }

    return XLLP_STATUS_SUCCESS;
}


///////////////////////////////////////////
static int platform_id = 0;
static void detect_platform(P_XLLP_U2D_T pU2DHandle);

static XLLP_UINT32_T xllp_u2d_mfp_list[] =
{

#ifndef CONFIG_CPU_MONAHANS_LV
    XLLP_MFP_U2D_UTM_CLK_OFFSET,

    XLLP_MFP_U2D_DATA0_OFFSET   ,

    XLLP_MFP_U2D_DATA1_OFFSET   ,

    XLLP_MFP_U2D_DATA2_OFFSET   ,

    XLLP_MFP_U2D_DATA3_OFFSET   ,

    XLLP_MFP_U2D_DATA4_OFFSET   ,

    XLLP_MFP_U2D_DATA5_OFFSET   ,

    XLLP_MFP_U2D_DATA6_OFFSET   ,

    XLLP_MFP_U2D_DATA7_OFFSET       ,

    XLLP_MFP_U2D_RESET_OFFSET   ,

    XLLP_MFP_U2D_XCVR_SELECT_OFFSET,

    XLLP_MFP_U2D_TERM_SELECT_OFFSET,

    XLLP_MFP_U2D_SUSPENDM_X_OFFSET ,

    XLLP_MFP_U2D_LINESTATE0_OFFSET ,

    XLLP_MFP_U2D_LINESTATE1_OFFSET ,


    XLLP_MFP_U2D_TXVALID_OFFSET     ,

    XLLP_MFP_U2D_TXREADY_OFFSET     ,

    XLLP_MFP_U2D_RXVALID_OFFSET     ,

    XLLP_MFP_U2D_RXACTIVE_OFFSET    ,

    XLLP_MFP_U2D_RXERROR_OFFSET     ,

    XLLP_MFP_U2D_OPMODE0_OFFSET     ,

    XLLP_MFP_U2D_OPMODE1_OFFSET     ,
#else
    XLLP_MPF_PIN_ULPI_STP_OFFSET,
    XLLP_MPF_PIN_ULPI_DIR_OFFSET,
    XLLP_MPF_PIN_ULPI_NXT_OFFSET,

    XLLP_MFP_ULPI_CLK_OFFSET,

    XLLP_MFP_ULPI_DATA0_OFFSET  ,

    XLLP_MFP_ULPI_DATA1_OFFSET  ,

    XLLP_MFP_ULPI_DATA2_OFFSET  ,

    XLLP_MFP_ULPI_DATA3_OFFSET  ,

    XLLP_MFP_ULPI_DATA4_OFFSET  ,

    XLLP_MFP_ULPI_DATA5_OFFSET  ,

    XLLP_MFP_ULPI_DATA6_OFFSET  ,

    XLLP_MFP_ULPI_DATA7_OFFSET  ,

    XLLP_MFP_ULPI_RESET     ,

#endif

    XLLP_MFP_PIN_EOLIST_MARKER
};

static XLLP_MFP_ALT_FN_T xllp_u2d_af_list[] =
{
#ifndef CONFIG_CPU_MONAHANS_LV
    XLLP_MFP_U2D_UTM_CLK_AF         ,

    XLLP_MFP_U2D_DATA0_AF           ,

    XLLP_MFP_U2D_DATA1_AF           ,

    XLLP_MFP_U2D_DATA2_AF           ,

    XLLP_MFP_U2D_DATA3_AF           ,

    XLLP_MFP_U2D_DATA4_AF           ,

    XLLP_MFP_U2D_DATA5_AF           ,

    XLLP_MFP_U2D_DATA6_AF           ,

    XLLP_MFP_U2D_DATA7_AF               ,

    XLLP_MFP_U2D_RESET_AF           ,

    XLLP_MFP_U2D_XCVR_SELECT_AF     ,

    XLLP_MFP_U2D_TERM_SELECT_AF     ,

    XLLP_MFP_U2D_SUSPENDM_X_AF      ,

    XLLP_MFP_U2D_LINESTATE0_AF      ,

    XLLP_MFP_U2D_LINESTATE1_AF      ,

    XLLP_MFP_U2D_TXVALID_AF         ,

    XLLP_MFP_U2D_TXREADY_AF         ,

    XLLP_MFP_U2D_RXVALID_AF         ,

    XLLP_MFP_U2D_RXACTIVE_AF        ,

    XLLP_MFP_U2D_RXERROR_AF         ,

    XLLP_MFP_U2D_OPMODE0_AF         ,

    XLLP_MFP_U2D_OPMODE1_AF
#else
    XLLP_MFP_ALT_FN_0,
    XLLP_MFP_ALT_FN_0,
    XLLP_MFP_ALT_FN_0,

    XLLP_MFP_ULPI_CLK_AF,

    XLLP_MFP_ULPI_DATA0_AF  ,

    XLLP_MFP_ULPI_DATA1_AF  ,

    XLLP_MFP_ULPI_DATA2_AF  ,

    XLLP_MFP_ULPI_DATA3_AF  ,

    XLLP_MFP_ULPI_DATA4_AF  ,

    XLLP_MFP_ULPI_DATA5_AF  ,

    XLLP_MFP_ULPI_DATA6_AF  ,

    XLLP_MFP_ULPI_DATA7_AF      ,

    XLLP_MFP_ULPI_RESET_AF  ,

#endif

};

#define XLLP_MFP_USB2_DEFAULT_DS    XLLP_MFP_DS_12X

static XLLP_MFP_DRIVE_STRENGTH_T xllp_u2d_ds_list[] =
{
#ifndef CONFIG_CPU_MONAHANS_LV
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,


// 8


    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

// 16
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
#else
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,
    XLLP_MFP_USB2_DEFAULT_DS,

    XLLP_MFP_USB2_DEFAULT_DS,

#endif
};

/* kv - Initialise platform detection pins to GPIO */
#define XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS XLLP_MFP_DS_01X

static XLLP_UINT32_T xllp_platform_detect_mfp_list[] =
{
    XLLP_MFP_PLATFORM_DETECT_0,
    XLLP_MFP_PLATFORM_DETECT_1,
    XLLP_MFP_PLATFORM_DETECT_2,
    XLLP_MFP_PLATFORM_DETECT_3,
    XLLP_MFP_PLATFORM_DETECT_4,
    XLLP_MFP_PLATFORM_DETECT_5,
    XLLP_MFP_PLATFORM_DETECT_6,
    XLLP_MFP_PIN_EOLIST_MARKER
};

static XLLP_MFP_ALT_FN_T xllp_platform_detect_af_list[] =
{
    XLLP_MFP_PLATFORM_DETECT_0_AF,
    XLLP_MFP_PLATFORM_DETECT_1_AF,
    XLLP_MFP_PLATFORM_DETECT_2_AF,
    XLLP_MFP_PLATFORM_DETECT_3_AF,
    XLLP_MFP_PLATFORM_DETECT_4_AF,
    XLLP_MFP_PLATFORM_DETECT_5_AF,
    XLLP_MFP_PLATFORM_DETECT_6_AF,
};

static XLLP_MFP_DRIVE_STRENGTH_T xllp_platform_detect_ds_list[] =
{
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
    XLLP_MFP_PLATFORM_DETECT_DEFAULT_DS,
};


/*this function should be optimize when transplant*/

void XllpU2DPlatformInit(P_XLLP_U2D_T pU2DHandle)
{
    unsigned char val;

    return;

    detect_platform(pU2DHandle);
    if (1 == platform_id) { /* Littleton Rev 1.x */
        xllp_max7320_read(0, &val);
        val |= 0x2;
        xllp_max7320_write(0, val);
    } else {
//#define   ULPI_RESET_ECO
#ifndef ULPI_RESET_ECO
        XllpGpioSetDirection (pU2DHandle->pGPIORegs,
                XLLP_GPIO_ULPI_RESET,
                XLLP_GPIO_DIRECTION_OUT);
        XllpGpioSetOutputLevel(pU2DHandle->pGPIORegs,
                XLLP_GPIO_ULPI_RESET,
                XLLP_HI);
#else
        int count;
        XllpGpioSetDirection(pU2DHandle->pGPIORegs,
                XLLP_GPIO_ULPI_RESET,
                XLLP_GPIO_DIRECTION_OUT);

        XllpGpioSetOutputLevel(pU2DHandle->pGPIORegs,
                XLLP_GPIO_ULPI_RESET,
                XLLP_LO);
#endif

    }

    //XLLP_STATUS_WRONG_PARAMETER
    XllpMfpSetAfDs_List(pU2DHandle->pMfpRegBase,
                xllp_u2d_mfp_list,
                xllp_u2d_af_list,
                xllp_u2d_ds_list);

    XllpMfpActivatePullUpDown_List(pU2DHandle->pMfpRegBase,
                xllp_u2d_mfp_list,
                XLLP_OFF);


}

static void detect_platform(P_XLLP_U2D_T pU2DHandle)
{
    int i, board_id = 0;
    int board_detect_pins[7] = {
        XLLP_GPIO_PLATFORM_DETECT_0_N,
        XLLP_GPIO_PLATFORM_DETECT_1_N,
        XLLP_GPIO_PLATFORM_DETECT_2_N,
        XLLP_GPIO_PLATFORM_DETECT_3_N,
        XLLP_GPIO_PLATFORM_DETECT_4_N,
        XLLP_GPIO_PLATFORM_DETECT_5_N,
        XLLP_GPIO_PLATFORM_DETECT_6_N,
    };

    XLLP_LEVEL_T level = XLLP_LO;
    XllpMfpSetAfDs_List(pU2DHandle->pMfpRegBase,
            xllp_platform_detect_mfp_list,
            xllp_platform_detect_af_list,
            xllp_platform_detect_ds_list);

    XllpMfpActivatePullUpDown_List(pU2DHandle->pMfpRegBase,
            xllp_platform_detect_mfp_list,
            XLLP_OFF);

    /* set detect pins as gpio input */
    for (i = 6; i >= 0; i--) {
        XllpGpioGetLevel(pU2DHandle->pGPIORegs,
                board_detect_pins[i],
                &level);
        board_id = (level << i) | board_id;
    }

    platform_id = (board_id >> 4);
    DBGOUT(printf("platform_id %x\n",platform_id));
}
